
#include <QtGui>
#include <QtNetwork>
#include <algorithm>
#include "window.h"

using namespace std;

Window::Window(QApplication *a)
:app(a)
{
    accountGroupBox = new QGroupBox(tr("SSH Account List"));
    accountView = new QTreeView;
    accountView->setRootIsDecorated(false);
    accountView->setAlternatingRowColors(true);
    accountView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    connect(accountView, SIGNAL(activated(const QModelIndex & index)),
        this, SLOT(itemActivated(const QModelIndex & index)));

    refreshButton = new QPushButton(tr("Refresh"));
    checkButton = new QPushButton(tr("Check"));
    addButton = new QPushButton(tr("Add"));
    removeButton = new QPushButton(tr("Remove"));
    exportButton = new QPushButton(tr("Export"));
    importButton = new QPushButton(tr("Import"));

    QGridLayout *accountLayout = new QGridLayout;
    accountLayout->addWidget(accountView, 0, 0, 1, 3);
    accountLayout->addWidget(refreshButton, 1, 0);
    accountLayout->addWidget(addButton, 1, 1);
    accountLayout->addWidget(exportButton, 1, 2);
    accountLayout->addWidget(checkButton, 2, 0);
    accountLayout->addWidget(removeButton, 2, 1);
    accountLayout->addWidget(importButton, 2, 2);

    accountGroupBox->setLayout(accountLayout);
    
    //--------------------------------------------------------------------
    connectionGroupBox = new QGroupBox(tr("Connection"));

    addressEdit = new QLineEdit;
    addressLabel = new QLabel(tr("SSH Server:"));
    addressLabel->setBuddy(addressEdit);

    portEdit = new QLineEdit;
    portLabel = new QLabel(tr("SSH Port:"));
    portLabel->setBuddy(portEdit);

    usernameEdit = new QLineEdit;
    usernameLabel = new QLabel(tr("User Name:"));
    usernameLabel->setBuddy(usernameEdit);

    passwordEdit = new QLineEdit;
    passwordLabel = new QLabel(tr("Password:"));
    passwordLabel->setBuddy(passwordEdit);

    latencyEdit = new QLineEdit;
    latencyLabel = new QLabel(tr("Latency:"));
    latencyLabel->setBuddy(latencyEdit);

    localPortEdit = new QLineEdit;
    localPortLabel = new QLabel(tr("Local Port:"));
    localPortLabel->setBuddy(localPortEdit);

    autoReconnFailedCheckBox = new QCheckBox(tr("Auto re-connect when failed."));
    autoConnStartupCheckBox = new QCheckBox(tr("Auto connect at startup"));
    slowQueryCheckBox = new QCheckBox(tr("Slow query"));
    noLimitedRetryCheckBox = new QCheckBox(tr("No limitation retry"));
    usingPrivateKeyCheckBox = new QCheckBox(tr("Using private key"));
    dynamicSocketCheckBox = new QCheckBox(tr("Using dynamic socket"));
    verboseLogCheckBox = new QCheckBox(tr("Verbose log"));
    hidePortCheckBox = new QCheckBox(tr("Hide port"));
    disablePromptCheckBox = new QCheckBox(tr("Disable prompt"));
    enableCompressionCheckBox = new QCheckBox(tr("Enable compression"));

    QGridLayout *connectionLayout = new QGridLayout;
    connectionLayout->addWidget(addressLabel, 0, 0);
    connectionLayout->addWidget(addressEdit, 0, 1);
    connectionLayout->addWidget(portLabel, 0, 2);
    connectionLayout->addWidget(portEdit, 0, 3);
    connectionLayout->addWidget(usernameLabel, 1, 0);
    connectionLayout->addWidget(usernameEdit, 1, 1);
    connectionLayout->addWidget(passwordLabel, 1, 2);
    connectionLayout->addWidget(passwordEdit, 1, 3);
    connectionLayout->addWidget(latencyLabel, 2, 0);
    connectionLayout->addWidget(latencyEdit, 2, 1);
    connectionLayout->addWidget(localPortLabel, 2, 2);
    connectionLayout->addWidget(localPortEdit, 2, 3);
    connectionLayout->addWidget(autoConnStartupCheckBox, 3, 0, 1, 2);
    connectionLayout->addWidget(slowQueryCheckBox, 3, 2, 1, 2);
    connectionLayout->addWidget(autoReconnFailedCheckBox, 4, 0, 1, 2);
    connectionLayout->addWidget(noLimitedRetryCheckBox, 4, 2, 1, 2);
    connectionLayout->addWidget(usingPrivateKeyCheckBox, 5, 0, 1, 2);
    connectionLayout->addWidget(dynamicSocketCheckBox, 5, 2, 1, 2);
    connectionLayout->addWidget(verboseLogCheckBox, 6, 0, 1, 2);
    connectionLayout->addWidget(hidePortCheckBox, 6,2, 1, 2);
    connectionLayout->addWidget(disablePromptCheckBox, 7, 0, 1, 2);
    connectionLayout->addWidget(enableCompressionCheckBox, 7, 2, 1, 2);
    connectionGroupBox->setLayout(connectionLayout);
    //-----------------------------------------------------------------
    keyFeatureGroupBox = new QGroupBox;
    hideButton = new QPushButton(tr("Hide window"));
    aboutButton = new QPushButton(tr("About"));
    connectButton = new QPushButton(tr("Connect")) ;
    exitButton = new QPushButton(tr("Exit")) ;

    QGridLayout *keyFeatureButtonLayout = new QGridLayout;
    keyFeatureButtonLayout->addWidget(connectButton, 0, 0);
    keyFeatureButtonLayout->addWidget(hideButton, 0, 1);
    keyFeatureButtonLayout->addWidget(aboutButton, 0, 2);
    keyFeatureButtonLayout->addWidget(exitButton, 0, 3);
    connect(exitButton, SIGNAL(clicked()), a, SLOT(quit()));

    keyFeatureGroupBox->setLayout(keyFeatureButtonLayout);
    //-----------------------------------------------------------------
    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(accountGroupBox);
    mainLayout->addWidget(connectionGroupBox);
    mainLayout->addWidget(keyFeatureGroupBox);
    setLayout(mainLayout);

    setWindowTitle(tr("Tremella"));
    resize(500, 500);

    connect(&qnam, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
        this, SLOT(slotAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
#ifndef QT_NO_OPENSSL
    connect(&qnam, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
        this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
#endif

    url = QUrl("http://tremella.googlecode.com/svn/trunk/accouts.txt");
    downloadFile();
}

void Window::setSourceModel(QAbstractItemModel *model)
{
    accountView->setModel(model);
}

void Window::addAccount( QAbstractItemModel *model, const QString &address, const QString &username, const QString &password, const QString &port, const QString &available )
{
    model->insertRow(0);
    model->setData(model->index(0, 0), address);
    model->setData(model->index(0, 1), username);
    model->setData(model->index(0, 2), password);
    model->setData(model->index(0, 3), port);
    model->setData(model->index(0, 4), available);
}

QAbstractItemModel * Window::createMailModel( QObject *parent )
{
    QStandardItemModel *model = new QStandardItemModel(0, 5, parent);

    model->setHeaderData(0, Qt::Horizontal, QObject::tr("Address"));
    model->setHeaderData(1, Qt::Horizontal, QObject::tr("Username"));
    model->setHeaderData(2, Qt::Horizontal, QObject::tr("Password"));
    model->setHeaderData(3, Qt::Horizontal, QObject::tr("Port"));
    model->setHeaderData(4, Qt::Horizontal, QObject::tr("Available"));

    // read data from http://tremella.googlecode.com/svn/trunk/accouts.txt

    QString fileName = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
    fileName.append("/accounts.txt");
    QFile file(fileName);
    if (file.exists() && file.open(QIODevice::ReadOnly)) {
        QByteArray content = QByteArray::fromBase64(file.readAll());
        QList<QByteArray> arr = content.split('\n');
        QList<QByteArray> accounts;
        for (QList<QByteArray>::iterator it = arr.begin();
            arr.end() != it;
            ++it) {
            QList<QByteArray> newarr = it->split('\r');
            std::copy(newarr.begin(), newarr.end(), back_inserter(accounts));
        }
        // fill all accounts into view
        for (QList<QByteArray>::iterator it = accounts.begin();
            accounts.end() != it;
            ++it) {
                QList<QByteArray> info = it->split(':');
                if (info.size() == 4) {
                    addAccount(model,
                        QString(info[0].data()),
                        QString(info[1].data()),
                        QString(info[2].data()),
                        QString(info[3].data()),
                        "");
                }
        }
    }

    return model;
}

void Window::startRequest( QUrl url )
{
    reply = qnam.get(QNetworkRequest(url));
    connect(reply, SIGNAL(finished()),
        this, SLOT(httpFinished()));
    connect(reply, SIGNAL(readyRead()),
        this, SLOT(httpReadyRead()));
}

void Window::httpFinished()
{
    file->flush();
    file->close();

    QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
    if (reply->error()) {
        file->remove();
    } else if (!redirectionTarget.isNull()) {        
        QUrl newUrl = url.resolved(redirectionTarget.toUrl());
        url = newUrl;
        reply->deleteLater();
        file->open(QIODevice::WriteOnly);
        file->resize(0);
        startRequest(url);
        return;
    } else {
        QString fileName = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
        QString targetFileName = fileName;
        fileName.append("/accounts.txt.bak");
        targetFileName.append("/accounts.txt");
        QFile::rename(fileName, targetFileName);

        setSourceModel(createMailModel(this));
    }

    reply->deleteLater();
    reply = 0;
    delete file;
    file = 0;
}

void Window::httpReadyRead()
{
    // this slot gets called every time the QNetworkReply has new data.
    // We read all of its new data and write it into the file.
    // That way we use less RAM than when reading it at the finished()
    // signal of the QNetworkReply
    if (file)
        file->write(reply->readAll());
}

void Window::downloadFile()
{
    QFileInfo fileInfo(url.path());
    QString fileName = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
    fileName.append("/accounts.txt.bak");

    if (QFile::exists(fileName)) {
        QFile::remove(fileName);
    }

    file = new QFile(fileName);
    if (!file->open(QIODevice::WriteOnly)) {
        delete file;
        file = 0;
        return;
    }

    // schedule the request
    startRequest(url);
}

void Window::itemActivated( const QModelIndex & index )
{
    Q_UNUSED(index);
}
